﻿using System;
using System.Text;
using System.Windows.Forms;
using System.Drawing;
using System.Windows.Forms.VisualStyles;

namespace DotNet.Common
{
    public partial class MacAddressBox : ContainerControl
    {
        const int FieldCount = 6;
        HexByteControl[] _hexByteControls;
        GapControl[] _gapControls;
        bool _backColorEnable;
        Color _backColor;

        public override string Text
        {
            get
            {
                return this.ToString();
            }
            set
            {
                Parse(value);
            }
        }

        string _separator = ".";
        public string Separator
        {
            get { return _separator; }
            set
            {
                _separator = value;
                foreach (GapControl gap in _gapControls)
                {
                    gap.Text = value;
                    gap.Size = gap.MinimumSize;
                }
                this.OnSizeChanged(EventArgs.Empty);
            }
        }

        public override Size MinimumSize
        {
            get
            {
                Size minimumSize = new Size(0, 0);

                minimumSize.Width += MacAddressBox.FieldCount * _hexByteControls[0].Width;
                minimumSize.Width += (MacAddressBox.FieldCount - 1) * _gapControls[0].Width;
                minimumSize.Width += 4;

                minimumSize.Height = Math.Max(_hexByteControls[0].Height, _gapControls[0].Height);
                minimumSize.Height += 7;

                return minimumSize;
            }
        }

        public byte[] MacBytes
        {
            get
            {
                byte[] bytes = new byte[MacAddressBox.FieldCount];

                for (int index = 0; index < MacAddressBox.FieldCount; ++index)
                {
                    bytes[index] = _hexByteControls[index].Value;
                }

                return bytes;
            }
            set
            {
                if (value == null || value.Length != 6)
                    return;

                for (int index = 0; index < MacAddressBox.FieldCount; ++index)
                {
                    _hexByteControls[index].Value = value[index];
                }
            }
        }

        public MacAddressBox()
        {
            _hexByteControls = new HexByteControl[MacAddressBox.FieldCount];
            _gapControls = new GapControl[MacAddressBox.FieldCount - 1];

            int i;
            HexByteControl oHexByteControl;
            GapControl oGapControl;
            for (i = 0; i < MacAddressBox.FieldCount; i++)
            {
                oHexByteControl = new HexByteControl();
                oHexByteControl.Parent = this;
                oHexByteControl.Index = i;
                oHexByteControl.FocusAction += new EventHandler<FocusMoveEventArgs>(oHexByteControl_FocusMove);

                _hexByteControls[i] = oHexByteControl;
                base.Controls.Add(oHexByteControl);

                if (i == MacAddressBox.FieldCount - 1)
                    break;

                oGapControl = new GapControl(_separator);
                oGapControl.Parent = this;

                _gapControls[i] = oGapControl;
                base.Controls.Add(oGapControl);
            }

            _backColorEnable = true;
            base.BackColor = SystemColors.Window;
        }

        public void Clear()
        {
            foreach (HexByteControl fc in _hexByteControls)
            {
                fc.Clear();
            }
        }

        public override string ToString()
        {
            StringBuilder sb = new StringBuilder();

            for (int index = 0; index < MacAddressBox.FieldCount; index++)
            {
                sb.Append(_hexByteControls[index].Text);

                if (index == MacAddressBox.FieldCount - 1)
                    break;

                sb.Append(_separator);
            }

            return sb.ToString();
        }

        protected override void OnFontChanged(EventArgs e)
        {
            base.OnFontChanged(e);
            AdjustSize();
        }

        protected override void OnSizeChanged(EventArgs e)
        {
            base.OnSizeChanged(e);
            AdjustSize();
        }

        protected override void OnEnabledChanged(EventArgs e)
        {
            base.OnEnabledChanged(e);

            _backColorEnable = false;
            base.BackColor = this.Enabled ? _backColor : SystemColors.Control;
            _backColorEnable = true;
        }

        protected override void OnBackColorChanged(EventArgs e)
        {
            base.OnBackColorChanged(e);
            if (_backColorEnable)
                _backColor = base.BackColor;
        }

        protected override void OnPaint(PaintEventArgs e)
        {
            base.OnPaint(e);

            using (Pen pen = new Pen(VisualStyleInformation.TextControlBorder))
            {
                Rectangle rectBorder = new Rectangle(base.ClientRectangle.Left, base.ClientRectangle.Top,
                    base.ClientRectangle.Width - 1, base.ClientRectangle.Height - 1);
                e.Graphics.DrawRectangle(pen, rectBorder);
            }
        }

        private void AdjustSize()
        {
            base.Size = this.MinimumSize;

            LayoutControls();
        }

        private void LayoutControls()
        {
            this.SuspendLayout();

            int x = 2, y = 3;
            for (int i = 0; i < MacAddressBox.FieldCount; ++i)
            {
                _hexByteControls[i].Location = new Point(x, y);
                x += _hexByteControls[i].Width;

                if (i == MacAddressBox.FieldCount - 1)
                    break;

                _gapControls[i].Location = new Point(x, y);
                x += _gapControls[i].Width;
            }

            this.ResumeLayout(false);
        }

        private void Parse(String text)
        {
            Clear();

            if (null == text)
            {
                return;
            }

            string subText;
            int textIndex = 0;
            for (int index = 0; index < MacAddressBox.FieldCount; index++)
            {
                int findIndex = text.IndexOf(_separator, textIndex, StringComparison.Ordinal);

                if (findIndex < 0)
                {
                    if (index == MacAddressBox.FieldCount - 1)
                    {
                        subText = text.Substring(textIndex);
                    }
                    else
                    {
                        break;
                    }
                }
                else
                {
                    subText = text.Substring(textIndex, findIndex - textIndex);
                    textIndex = findIndex + _separator.Length;
                }

                byte result;
                if (byte.TryParse(subText, System.Globalization.NumberStyles.HexNumber, null, out result))
                {
                    _hexByteControls[index].Text = subText.ToUpper();
                }
            }
        }

        private void oHexByteControl_FocusMove(object sender, FocusMoveEventArgs e)
        {
            int index = 0;
            switch (e.Action)
            {
                case MoveAction.Left:
                    if (e.Index == 0)
                        return;

                    index = e.Index - 1;
                    break;
                case MoveAction.Right:
                    if (e.Index == MacAddressBox.FieldCount - 1)
                        return;

                    index = e.Index + 1;
                    break;
                case MoveAction.Home:
                    index = 0;
                    break;
                case MoveAction.End:
                    index = MacAddressBox.FieldCount - 1;
                    break;
            }
            _hexByteControls[index].Focus();
        }
    }
}
